from typing import List, Dict, Tuple
from FileLoader import Interaction
import torch


class InteractScore:
    def __init__(self, hyper_params):
        self.hyper_params = hyper_params

    def get_interact_score(self, user_interact_list: List[Interaction]) -> Tuple[Dict[int, float], Dict[int, torch.Tensor]]:
        interact_dict: Dict[int, Dict[int, List[Interaction]]] = {}

        # Group By interaction_type and book ID
        for interact in user_interact_list:
            if interact.interaction_type not in interact_dict:
                interact_dict[interact.interaction_type] = {}

            if interact.item_id not in interact_dict[interact.interaction_type]:
                interact_dict[interact.interaction_type][interact.item_id] = []

            interact_dict[interact.interaction_type][interact.item_id].append(
                interact)

        # Process each interaction_type respectively
        result: Dict[int, float] = {}
        extra_info: Dict[int, torch.Tensor] = {}

        for interact_type, book_hist in interact_dict.items():
            if interact_type == 0:
                # enter the reading page
                for book_id, hist in book_hist.items():
                    result[book_id] = float(len(hist))

            elif interact_type == 1:
                # enter the information page
                for book_id, hist in book_hist.items():
                    result[book_id] = 0.5 * float(len(hist))
                    # half as much as reading

            elif interact_type == 2:
                # time of staying in recommendation page
                for book_id, hist in book_hist.items():
                    for inte in hist:
                        result[book_id] += inte.info/10
                        # Normally the time will be short, we can use it directly

            elif interact_type == 3:  # scroll speed
                # Not Implemented
                raise NotImplementedError()

            elif interact_type == 4:
                # user score
                for book_id, hist in book_hist.items():
                    for inte in hist:
                        result[book_id] += inte.info
                        # If full mark is not large, such as 5, we can directly use it

            elif interact_type == 5:
                # user like it
                for book_id, hist in book_hist.items():
                    result[book_id] = 5
                    # the return value can be same as full mark

            elif interact_type == 6:
                # user dislike it
                for book_id, hist in book_hist.items():
                    result[book_id] = 0
                    # return 0 or a negative value

            else:
                # Not Implemented
                raise NotImplementedError()

            # Extra Info (Calculate Average Values)
            for book_id, hist in book_hist.items():
                cur_extra = torch.zeros(
                    self.hyper_params['extra_dim'], dtype=torch.float32)
                cur_extra_cnt = 0
                for interact in hist:
                    if interact.extra_info is not None:
                        cur_extra += torch.FloatTensor(interact.extra_info)
                        cur_extra_cnt += 1

                if cur_extra_cnt > 0:
                    cur_extra /= float(cur_extra_cnt)

                extra_info[book_id] = cur_extra

        return result, extra_info
